Skip to content

feat(data-pipeline)!: OTLP gRPC trace export - #2171

Open
bm1549 wants to merge 7 commits into
mainfrom
brian.marks/otlp-grpc-trace-export
Open

feat(data-pipeline)!: OTLP gRPC trace export#2171
bm1549 wants to merge 7 commits into
mainfrom
brian.marks/otlp-grpc-trace-export

Conversation

@bm1549

@bm1549 bm1549 commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds OTLP gRPC as a trace-export transport, selectable with OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=grpc. OtlpProtocol gains a Grpc variant, and TraceExporter dispatches through OtlpExportMode (Http or Grpc). The gRPC path limits response bodies to 4 MiB and reports partial-success responses. Remote-status diagnostics retain the original gRPC code. OTLP resource metadata is built once when the exporter is constructed, including the client-computed-stats marker. gRPC is native-only; wasm32 rejects it during build. The FFI accepts grpc, so SDKs using libdatadog can select the transport.

The transport validates its dial authority before creating the exporter. Portless http:// endpoints use port 80. Valid explicit DNS and IPv6 ports are preserved; empty hosts, malformed ports, and userinfo are rejected. Retryable gRPC errors use bounded exponential backoff with jitter. RESOURCE_EXHAUSTED is retried only when the server supplies google.rpc.RetryInfo. A positive server delay is used as the backoff base when it fits within the 30-second retry budget; longer delays stop retries instead of retrying before the server requested. Zero or missing delays use the existing 100 ms base. Protobuf requests are shared across attempts instead of deep-cloned.

The fork-safe gRPC transport primitive landed in #2273. This PR integrates it with the exporter and FFI and includes the transport hardening found during review. Completed responses now win over subsequent connection teardown, and transient HTTP/2 stream resets are classified as retryable transport errors. Remote gRPC statuses keep their code and status classification instead of being reported as local I/O failures. The gRPC path sends the standard libdatadog user-agent and entity headers and emits the native trace-export telemetry now used by the other transports.

Motivation

libdatadog's OTLP trace export was HTTP-only. Java and .NET implement gRPC OTLP separately; PHP, Python, Ruby, and Rust use libdatadog for trace export. Adding gRPC here lets their integrations honor OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=grpc instead of rejecting it or falling back to another transport.

Additional Notes

  • The transport from feat(data-pipeline): add fork-safe OTLP gRPC trace transport #2273 is a custom tonic GrpcService over hyper h2c. It creates a connection per request and has no persistent worker, which keeps it safe across forks.
  • OtlpProtocol::from_str("grpc") now succeeds. Adding a variant to the exhaustive public enum is a breaking change, as noted in the commit footer.
  • Transient IO and the retryable gRPC codes (Cancelled, Aborted, OutOfRange, DataLoss, Unavailable, and DeadlineExceeded) get OTLP_MAX_RETRIES + 1 total attempts. RetryInfo controls recoverable throttling delays; other retries use the existing 100 ms exponential base, with up to 100 ms of jitter.
  • Remote gRPC statuses map to compatible HTTP statuses for the existing RequestError and FFI error classification, while retaining the gRPC code in the message.
  • Both OTLP transports preserve .set_client_computed_stats() in the resource attributes and request metadata.
  • The current transport is plaintext h2c. TLS support and an FFI setter for custom OTLP headers remain follow-ups; the FFI header limitation also applies to HTTP OTLP.

How to test the change?

  • cargo check -p libdd-data-pipeline
  • cargo +nightly-2026-07-26 fmt --all -- --check
  • cargo +stable clippy -p libdd-data-pipeline --all-targets --no-deps -- -D warnings
  • cargo +nightly clippy -p libdd-data-pipeline --test test_trace_exporter_otlp_grpc -- -D warnings
  • cargo +1.87.0 check -p libdd-data-pipeline --test test_trace_exporter_otlp_grpc
  • cargo nextest run -p libdd-data-pipeline -E '!test(tracing_integration_tests::)' (204 passed; 7 Docker-backed integration tests skipped locally)
  • cargo test -p libdd-data-pipeline grpc --lib (34 passed)
  • cargo test -p libdd-data-pipeline --test test_trace_exporter_otlp_grpc (2 passed)
  • cargo test -p libdd-data-pipeline --doc (2 passed)
  • cargo check -p libdd-data-pipeline --target wasm32-unknown-unknown --no-default-features
  • cargo ffi-test --skip-build --filter trace_exporter (1 passed; the full FFI build succeeded)
  • cargo +stable clippy -p libdd-data-pipeline --all-targets -- -D warnings currently stops on a pre-existing collapsible_match warning in libdd-trace-utils/src/tracer_payload.rs, which this PR does not modify.

@bm1549 bm1549 added the AI Generated PR largely written by AI tools label Jun 26, 2026
@datadog-official

datadog-official Bot commented Jun 26, 2026

Copy link
Copy Markdown

Tests

All CI checks and tests passed.

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 90.36%
Overall Coverage: 77.24% (+0.16%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: a6ae5e4 | Docs | View more details | Give us feedback!

@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

📚 Documentation Check Results

⚠️ 3464 documentation warning(s) found

📦 libdd-data-pipeline-ffi - 1405 warning(s)

📦 libdd-data-pipeline - 1294 warning(s)

📦 libdd-trace-utils - 765 warning(s)


Updated: 2026-09-03 05:57:00 UTC | Commit: ff70244 | missing-docs job results

@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

🔒 Cargo Deny Results

⚠️ 11 issue(s) found, showing only errors (advisories, bans, sources)

📦 libdd-data-pipeline-ffi - 4 error(s)

Show output
error[vulnerability]: Invalid pointer dereference in `fmt::Pointer` impl for `Atomic` and `Shared` when the underlying pointer is invalid
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:80:1
   │
80 │ crossbeam-epoch 0.9.18 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
   │
   ├ ID: RUSTSEC-2026-0204
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0204
   ├ Affected versions of `fmt::Display` dereference the underlying pointer. This causes a invalid pointer dereference e.g., when a pointer created with `Atomic::null` or `Shared::null`. `fmt::Debug` impls and pre-0.9 `fmt::Display` impls, which do not dereference pointers, are not affected by this issue.
   ├ Announcement: https://github.com/crossbeam-rs/crossbeam/pull/1276
   ├ Solution: Upgrade to >=0.9.20 (try `cargo update -p crossbeam-epoch`)
   ├ crossbeam-epoch v0.9.18
     └── crossbeam-deque v0.8.5
         └── rayon-core v1.12.1
             └── rayon v1.10.0
                 └── criterion v0.5.1
                     ├── libdd-common v5.2.0
                     │   ├── libdd-capabilities-impl v4.0.0
                     │   │   ├── libdd-data-pipeline v9.0.0
                     │   │   │   └── libdd-data-pipeline-ffi v43.0.0
                     │   │   ├── libdd-data-pipeline-ffi v43.0.0 (*)
                     │   │   ├── libdd-shared-runtime v3.0.0
                     │   │   │   ├── libdd-data-pipeline v9.0.0 (*)
                     │   │   │   ├── libdd-data-pipeline-ffi v43.0.0 (*)
                     │   │   │   ├── libdd-dogstatsd-client v5.0.0
                     │   │   │   │   ├── libdd-data-pipeline v9.0.0 (*)
                     │   │   │   │   └── libdd-trace-stats v8.0.0
                     │   │   │   │       └── libdd-data-pipeline v9.0.0 (*)
                     │   │   │   ├── libdd-telemetry v7.0.0
                     │   │   │   │   ├── libdd-data-pipeline v9.0.0 (*)
                     │   │   │   │   └── libdd-trace-stats v8.0.0 (*)
                     │   │   │   └── libdd-trace-stats v8.0.0 (*)
                     │   │   ├── (dev) libdd-telemetry v7.0.0 (*)
                     │   │   ├── libdd-trace-stats v8.0.0 (*)
                     │   │   └── libdd-trace-utils v11.0.0
                     │   │       ├── libdd-data-pipeline v9.0.0 (*)
                     │   │       ├── libdd-data-pipeline-core v1.0.0
                     │   │       │   └── libdd-data-pipeline v9.0.0 (*)
                     │   │       ├── (dev) libdd-data-pipeline-ffi v43.0.0 (*)
                     │   │       ├── libdd-trace-obfuscation v7.0.0
                     │   │       │   ├── libdd-data-pipeline v9.0.0 (*)
                     │   │       │   ├── libdd-data-pipeline-core v1.0.0 (*)
                     │   │       │   ├── libdd-data-pipeline-ffi v43.0.0 (*)
                     │   │       │   └── libdd-trace-stats v8.0.0 (*)
                     │   │       ├── libdd-trace-stats v8.0.0 (*)
                     │   │       └── (dev) libdd-trace-utils v11.0.0 (*)
                     │   ├── libdd-common-ffi v43.0.0
                     │   │   └── libdd-data-pipeline-ffi v43.0.0 (*)
                     │   ├── libdd-data-pipeline v9.0.0 (*)
                     │   ├── libdd-data-pipeline-core v1.0.0 (*)
                     │   ├── libdd-dogstatsd-client v5.0.0 (*)
                     │   ├── libdd-shared-runtime v3.0.0 (*)
                     │   ├── libdd-telemetry v7.0.0 (*)
                     │   ├── libdd-trace-obfuscation v7.0.0 (*)
                     │   ├── libdd-trace-stats v8.0.0 (*)
                     │   └── libdd-trace-utils v11.0.0 (*)
                     ├── (dev) libdd-data-pipeline v9.0.0 (*)
                     ├── (dev) libdd-ddsketch v1.1.1
                     │   ├── libdd-data-pipeline v9.0.0 (*)
                     │   ├── libdd-telemetry v7.0.0 (*)
                     │   └── libdd-trace-stats v8.0.0 (*)
                     ├── (dev) libdd-trace-normalization v4.0.0
                     │   ├── libdd-data-pipeline v9.0.0 (*)
                     │   └── libdd-trace-utils v11.0.0 (*)
                     ├── (dev) libdd-trace-obfuscation v7.0.0 (*)
                     ├── (dev) libdd-trace-stats v8.0.0 (*)
                     └── (dev) libdd-trace-utils v11.0.0 (*)

error[vulnerability]: h2 unbounded empty DATA frames
    ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:123:1
    │
123 │ h2 0.4.6 registry+https://github.com/rust-lang/crates.io-index
    │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
    │
    ├ ID: RUSTSEC-2026-0258
    ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0258
    ├ The h2 crate, used internally by hyper, had a flaw that would accept and queue empty DATA frames without limit.
      If streams were not actively drained, this could lead to unbounded memory usage, or a panic if the length overflows.
      
      Low severity.
      
      Patched in v0.4.16.
    ├ Announcement: https://github.com/hyperium/hyper/security/advisories/GHSA-q83h-524g-xf6h
    ├ Solution: Upgrade to >=0.4.16 (try `cargo update -p h2`)
    ├ h2 v0.4.6
      ├── hyper v1.6.0
      │   ├── httpmock v0.8.0-alpha.1
      │   │   ├── (dev) libdd-data-pipeline v9.0.0
      │   │   │   └── libdd-data-pipeline-ffi v43.0.0
      │   │   ├── (dev) libdd-data-pipeline-ffi v43.0.0 (*)
      │   │   ├── (dev) libdd-telemetry v7.0.0
      │   │   │   ├── libdd-data-pipeline v9.0.0 (*)
      │   │   │   └── libdd-trace-stats v8.0.0
      │   │   │       └── libdd-data-pipeline v9.0.0 (*)
      │   │   ├── (dev) libdd-trace-stats v8.0.0 (*)
      │   │   └── libdd-trace-utils v11.0.0
      │   │       ├── libdd-data-pipeline v9.0.0 (*)
      │   │       ├── libdd-data-pipeline-core v1.0.0
      │   │       │   └── libdd-data-pipeline v9.0.0 (*)
      │   │       ├── (dev) libdd-data-pipeline-ffi v43.0.0 (*)
      │   │       ├── libdd-trace-obfuscation v7.0.0
      │   │       │   ├── libdd-data-pipeline v9.0.0 (*)
      │   │       │   ├── libdd-data-pipeline-core v1.0.0 (*)
      │   │       │   ├── libdd-data-pipeline-ffi v43.0.0 (*)
      │   │       │   └── libdd-trace-stats v8.0.0 (*)
      │   │       ├── libdd-trace-stats v8.0.0 (*)
      │   │       └── (dev) libdd-trace-utils v11.0.0 (*)
      │   ├── hyper-rustls v0.27.7
      │   │   └── libdd-common v5.2.0
      │   │       ├── libdd-capabilities-impl v4.0.0
      │   │       │   ├── libdd-data-pipeline v9.0.0 (*)
      │   │       │   ├── libdd-data-pipeline-ffi v43.0.0 (*)
      │   │       │   ├── libdd-shared-runtime v3.0.0
      │   │       │   │   ├── libdd-data-pipeline v9.0.0 (*)
      │   │       │   │   ├── libdd-data-pipeline-ffi v43.0.0 (*)
      │   │       │   │   ├── libdd-dogstatsd-client v5.0.0
      │   │       │   │   │   ├── libdd-data-pipeline v9.0.0 (*)
      │   │       │   │   │   └── libdd-trace-stats v8.0.0 (*)
      │   │       │   │   ├── libdd-telemetry v7.0.0 (*)
      │   │       │   │   └── libdd-trace-stats v8.0.0 (*)
      │   │       │   ├── (dev) libdd-telemetry v7.0.0 (*)
      │   │       │   ├── libdd-trace-stats v8.0.0 (*)
      │   │       │   └── libdd-trace-utils v11.0.0 (*)
      │   │       ├── libdd-common-ffi v43.0.0
      │   │       │   └── libdd-data-pipeline-ffi v43.0.0 (*)
      │   │       ├── libdd-data-pipeline v9.0.0 (*)
      │   │       ├── libdd-data-pipeline-core v1.0.0 (*)
      │   │       ├── libdd-dogstatsd-client v5.0.0 (*)
      │   │       ├── libdd-shared-runtime v3.0.0 (*)
      │   │       ├── libdd-telemetry v7.0.0 (*)
      │   │       ├── libdd-trace-obfuscation v7.0.0 (*)
      │   │       ├── libdd-trace-stats v8.0.0 (*)
      │   │       └── libdd-trace-utils v11.0.0 (*)
      │   ├── hyper-util v0.1.17
      │   │   ├── httpmock v0.8.0-alpha.1 (*)
      │   │   ├── hyper-rustls v0.27.7 (*)
      │   │   ├── libdd-common v5.2.0 (*)
      │   │   └── libdd-data-pipeline v9.0.0 (*)
      │   ├── libdd-common v5.2.0 (*)
      │   ├── libdd-common-ffi v43.0.0 (*)
      │   ├── libdd-data-pipeline v9.0.0 (*)
      │   └── libdd-trace-utils v11.0.0 (*)
      └── libdd-data-pipeline v9.0.0 (*)

error[unsound]: Rand is unsound with a custom logger using `rand::rng()`
    ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:232:1
    │
232 │ rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index
    │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unsound advisory detected
    │
    ├ ID: RUSTSEC-2026-0097
    ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0097
    ├ It has been reported (by [@lopopolo](https://github.com/lopopolo)) that the `rand` library is [unsound](https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library) (i.e. that safe code using the public API can cause Undefined Behaviour) when all the following conditions are met:
      
      - The `log` and `thread_rng` features are enabled
      - A [custom logger](https://docs.rs/log/latest/log/#implementing-a-logger) is defined
      - The custom logger accesses `rand::rng()` (previously `rand::thread_rng()`) and calls any `TryRng` (previously `RngCore`) methods on `ThreadRng`
      - The `ThreadRng` (attempts to) reseed while called from the custom logger (this happens every 64 kB of generated data)
      - Trace-level logging is enabled or warn-level logging is enabled and the random source (the `getrandom` crate) is unable to provide a new seed
      
      `TryRng` (previously `RngCore`) methods for `ThreadRng` use `unsafe` code to cast `*mut BlockRng<ReseedingCore>` to `&mut BlockRng<ReseedingCore>`. When all the above conditions are met this results in an aliased mutable reference, violating the Stacked Borrows rules. Miri is able to detect this violation in sample code. Since construction of [aliased mutable references is Undefined Behaviour](https://doc.rust-lang.org/stable/nomicon/references.html), the behaviour of optimized builds is hard to predict.
    ├ Announcement: https://github.com/rust-random/rand/pull/1763
    ├ Solution: Upgrade to >=0.10.1 OR <0.10.0, >=0.9.3 OR <0.9.0, >=0.8.6 (try `cargo update -p rand`)
    ├ rand v0.8.5
      ├── libdd-common v5.2.0
      │   ├── libdd-capabilities-impl v4.0.0
      │   │   ├── libdd-data-pipeline v9.0.0
      │   │   │   └── libdd-data-pipeline-ffi v43.0.0
      │   │   ├── libdd-data-pipeline-ffi v43.0.0 (*)
      │   │   ├── libdd-shared-runtime v3.0.0
      │   │   │   ├── libdd-data-pipeline v9.0.0 (*)
      │   │   │   ├── libdd-data-pipeline-ffi v43.0.0 (*)
      │   │   │   ├── libdd-dogstatsd-client v5.0.0
      │   │   │   │   ├── libdd-data-pipeline v9.0.0 (*)
      │   │   │   │   └── libdd-trace-stats v8.0.0
      │   │   │   │       └── libdd-data-pipeline v9.0.0 (*)
      │   │   │   ├── libdd-telemetry v7.0.0
      │   │   │   │   ├── libdd-data-pipeline v9.0.0 (*)
      │   │   │   │   └── libdd-trace-stats v8.0.0 (*)
      │   │   │   └── libdd-trace-stats v8.0.0 (*)
      │   │   ├── (dev) libdd-telemetry v7.0.0 (*)
      │   │   ├── libdd-trace-stats v8.0.0 (*)
      │   │   └── libdd-trace-utils v11.0.0
      │   │       ├── libdd-data-pipeline v9.0.0 (*)
      │   │       ├── libdd-data-pipeline-core v1.0.0
      │   │       │   └── libdd-data-pipeline v9.0.0 (*)
      │   │       ├── (dev) libdd-data-pipeline-ffi v43.0.0 (*)
      │   │       ├── libdd-trace-obfuscation v7.0.0
      │   │       │   ├── libdd-data-pipeline v9.0.0 (*)
      │   │       │   ├── libdd-data-pipeline-core v1.0.0 (*)
      │   │       │   ├── libdd-data-pipeline-ffi v43.0.0 (*)
      │   │       │   └── libdd-trace-stats v8.0.0 (*)
      │   │       ├── libdd-trace-stats v8.0.0 (*)
      │   │       └── (dev) libdd-trace-utils v11.0.0 (*)
      │   ├── libdd-common-ffi v43.0.0
      │   │   └── libdd-data-pipeline-ffi v43.0.0 (*)
      │   ├── libdd-data-pipeline v9.0.0 (*)
      │   ├── libdd-data-pipeline-core v1.0.0 (*)
      │   ├── libdd-dogstatsd-client v5.0.0 (*)
      │   ├── libdd-shared-runtime v3.0.0 (*)
      │   ├── libdd-telemetry v7.0.0 (*)
      │   ├── libdd-trace-obfuscation v7.0.0 (*)
      │   ├── libdd-trace-stats v8.0.0 (*)
      │   └── libdd-trace-utils v11.0.0 (*)
      ├── libdd-data-pipeline v9.0.0 (*)
      ├── (dev) libdd-ddsketch v1.1.1
      │   ├── libdd-data-pipeline v9.0.0 (*)
      │   ├── libdd-telemetry v7.0.0 (*)
      │   └── libdd-trace-stats v8.0.0 (*)
      ├── (dev) libdd-trace-normalization v4.0.0
      │   ├── libdd-data-pipeline v9.0.0 (*)
      │   └── libdd-trace-utils v11.0.0 (*)
      ├── (dev) libdd-trace-stats v8.0.0 (*)
      ├── libdd-trace-utils v11.0.0 (*)
      └── proptest v1.5.0
          ├── (dev) libdd-common v5.2.0 (*)
          └── (dev) libdd-tinybytes v1.1.2
              ├── libdd-data-pipeline v9.0.0 (*)
              ├── (dev) libdd-data-pipeline-core v1.0.0 (*)
              ├── libdd-data-pipeline-ffi v43.0.0 (*)
              ├── (dev) libdd-tinybytes v1.1.2 (*)
              ├── (dev) libdd-trace-obfuscation v7.0.0 (*)
              └── libdd-trace-utils v11.0.0 (*)

error[vulnerability]: Denial of Service via Stack Exhaustion
    ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:306:1
    │
306 │ time 0.3.41 registry+https://github.com/rust-lang/crates.io-index
    │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
    │
    ├ ID: RUSTSEC-2026-0009
    ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0009
    ├ ## Impact
      
      When user-provided input is provided to any type that parses with the RFC 2822 format, a denial of
      service attack via stack exhaustion is possible. The attack relies on formally deprecated and
      rarely-used features that are part of the RFC 2822 format used in a malicious manner. Ordinary,
      non-malicious input will never encounter this scenario.
      
      ## Patches
      
      A limit to the depth of recursion was added in v0.3.47. From this version, an error will be returned
      rather than exhausting the stack.
      
      ## Workarounds
      
      Limiting the length of user input is the simplest way to avoid stack exhaustion, as the amount of
      the stack consumed would be at most a factor of the length of the input.
    ├ Announcement: https://github.com/time-rs/time/blob/main/CHANGELOG.md#0347-2026-02-05
    ├ Solution: Upgrade to >=0.3.47 (try `cargo update -p time`)
    ├ time v0.3.41
      └── tracing-appender v0.2.3
          └── libdd-log v1.0.0
              └── (dev) libdd-data-pipeline v9.0.0
                  └── libdd-data-pipeline-ffi v43.0.0

advisories FAILED, bans ok, sources ok

📦 libdd-data-pipeline - 4 error(s)

Show output
error[vulnerability]: Invalid pointer dereference in `fmt::Pointer` impl for `Atomic` and `Shared` when the underlying pointer is invalid
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:77:1
   │
77 │ crossbeam-epoch 0.9.18 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
   │
   ├ ID: RUSTSEC-2026-0204
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0204
   ├ Affected versions of `fmt::Display` dereference the underlying pointer. This causes a invalid pointer dereference e.g., when a pointer created with `Atomic::null` or `Shared::null`. `fmt::Debug` impls and pre-0.9 `fmt::Display` impls, which do not dereference pointers, are not affected by this issue.
   ├ Announcement: https://github.com/crossbeam-rs/crossbeam/pull/1276
   ├ Solution: Upgrade to >=0.9.20 (try `cargo update -p crossbeam-epoch`)
   ├ crossbeam-epoch v0.9.18
     └── crossbeam-deque v0.8.5
         └── rayon-core v1.12.1
             └── rayon v1.10.0
                 └── criterion v0.5.1
                     ├── libdd-common v5.2.0
                     │   ├── libdd-capabilities-impl v4.0.0
                     │   │   ├── libdd-data-pipeline v9.0.0
                     │   │   ├── libdd-shared-runtime v3.0.0
                     │   │   │   ├── libdd-data-pipeline v9.0.0 (*)
                     │   │   │   ├── libdd-dogstatsd-client v5.0.0
                     │   │   │   │   ├── libdd-data-pipeline v9.0.0 (*)
                     │   │   │   │   └── libdd-trace-stats v8.0.0
                     │   │   │   │       └── libdd-data-pipeline v9.0.0 (*)
                     │   │   │   ├── libdd-telemetry v7.0.0
                     │   │   │   │   ├── libdd-data-pipeline v9.0.0 (*)
                     │   │   │   │   └── libdd-trace-stats v8.0.0 (*)
                     │   │   │   └── libdd-trace-stats v8.0.0 (*)
                     │   │   ├── (dev) libdd-telemetry v7.0.0 (*)
                     │   │   ├── libdd-trace-stats v8.0.0 (*)
                     │   │   └── libdd-trace-utils v11.0.0
                     │   │       ├── libdd-data-pipeline v9.0.0 (*)
                     │   │       ├── libdd-data-pipeline-core v1.0.0
                     │   │       │   └── libdd-data-pipeline v9.0.0 (*)
                     │   │       ├── libdd-trace-obfuscation v7.0.0
                     │   │       │   ├── libdd-data-pipeline v9.0.0 (*)
                     │   │       │   ├── libdd-data-pipeline-core v1.0.0 (*)
                     │   │       │   └── libdd-trace-stats v8.0.0 (*)
                     │   │       ├── libdd-trace-stats v8.0.0 (*)
                     │   │       └── (dev) libdd-trace-utils v11.0.0 (*)
                     │   ├── libdd-data-pipeline v9.0.0 (*)
                     │   ├── libdd-data-pipeline-core v1.0.0 (*)
                     │   ├── libdd-dogstatsd-client v5.0.0 (*)
                     │   ├── libdd-shared-runtime v3.0.0 (*)
                     │   ├── libdd-telemetry v7.0.0 (*)
                     │   ├── libdd-trace-obfuscation v7.0.0 (*)
                     │   ├── libdd-trace-stats v8.0.0 (*)
                     │   └── libdd-trace-utils v11.0.0 (*)
                     ├── (dev) libdd-data-pipeline v9.0.0 (*)
                     ├── (dev) libdd-ddsketch v1.1.1
                     │   ├── libdd-data-pipeline v9.0.0 (*)
                     │   ├── libdd-telemetry v7.0.0 (*)
                     │   └── libdd-trace-stats v8.0.0 (*)
                     ├── (dev) libdd-trace-normalization v4.0.0
                     │   ├── libdd-data-pipeline v9.0.0 (*)
                     │   └── libdd-trace-utils v11.0.0 (*)
                     ├── (dev) libdd-trace-obfuscation v7.0.0 (*)
                     ├── (dev) libdd-trace-stats v8.0.0 (*)
                     └── (dev) libdd-trace-utils v11.0.0 (*)

error[vulnerability]: h2 unbounded empty DATA frames
    ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:117:1
    │
117 │ h2 0.4.6 registry+https://github.com/rust-lang/crates.io-index
    │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
    │
    ├ ID: RUSTSEC-2026-0258
    ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0258
    ├ The h2 crate, used internally by hyper, had a flaw that would accept and queue empty DATA frames without limit.
      If streams were not actively drained, this could lead to unbounded memory usage, or a panic if the length overflows.
      
      Low severity.
      
      Patched in v0.4.16.
    ├ Announcement: https://github.com/hyperium/hyper/security/advisories/GHSA-q83h-524g-xf6h
    ├ Solution: Upgrade to >=0.4.16 (try `cargo update -p h2`)
    ├ h2 v0.4.6
      ├── hyper v1.6.0
      │   ├── httpmock v0.8.0-alpha.1
      │   │   ├── (dev) libdd-data-pipeline v9.0.0
      │   │   ├── (dev) libdd-telemetry v7.0.0
      │   │   │   ├── libdd-data-pipeline v9.0.0 (*)
      │   │   │   └── libdd-trace-stats v8.0.0
      │   │   │       └── libdd-data-pipeline v9.0.0 (*)
      │   │   ├── (dev) libdd-trace-stats v8.0.0 (*)
      │   │   └── libdd-trace-utils v11.0.0
      │   │       ├── libdd-data-pipeline v9.0.0 (*)
      │   │       ├── libdd-data-pipeline-core v1.0.0
      │   │       │   └── libdd-data-pipeline v9.0.0 (*)
      │   │       ├── libdd-trace-obfuscation v7.0.0
      │   │       │   ├── libdd-data-pipeline v9.0.0 (*)
      │   │       │   ├── libdd-data-pipeline-core v1.0.0 (*)
      │   │       │   └── libdd-trace-stats v8.0.0 (*)
      │   │       ├── libdd-trace-stats v8.0.0 (*)
      │   │       └── (dev) libdd-trace-utils v11.0.0 (*)
      │   ├── hyper-rustls v0.27.7
      │   │   └── libdd-common v5.2.0
      │   │       ├── libdd-capabilities-impl v4.0.0
      │   │       │   ├── libdd-data-pipeline v9.0.0 (*)
      │   │       │   ├── libdd-shared-runtime v3.0.0
      │   │       │   │   ├── libdd-data-pipeline v9.0.0 (*)
      │   │       │   │   ├── libdd-dogstatsd-client v5.0.0
      │   │       │   │   │   ├── libdd-data-pipeline v9.0.0 (*)
      │   │       │   │   │   └── libdd-trace-stats v8.0.0 (*)
      │   │       │   │   ├── libdd-telemetry v7.0.0 (*)
      │   │       │   │   └── libdd-trace-stats v8.0.0 (*)
      │   │       │   ├── (dev) libdd-telemetry v7.0.0 (*)
      │   │       │   ├── libdd-trace-stats v8.0.0 (*)
      │   │       │   └── libdd-trace-utils v11.0.0 (*)
      │   │       ├── libdd-data-pipeline v9.0.0 (*)
      │   │       ├── libdd-data-pipeline-core v1.0.0 (*)
      │   │       ├── libdd-dogstatsd-client v5.0.0 (*)
      │   │       ├── libdd-shared-runtime v3.0.0 (*)
      │   │       ├── libdd-telemetry v7.0.0 (*)
      │   │       ├── libdd-trace-obfuscation v7.0.0 (*)
      │   │       ├── libdd-trace-stats v8.0.0 (*)
      │   │       └── libdd-trace-utils v11.0.0 (*)
      │   ├── hyper-util v0.1.17
      │   │   ├── httpmock v0.8.0-alpha.1 (*)
      │   │   ├── hyper-rustls v0.27.7 (*)
      │   │   ├── libdd-common v5.2.0 (*)
      │   │   └── libdd-data-pipeline v9.0.0 (*)
      │   ├── libdd-common v5.2.0 (*)
      │   ├── libdd-data-pipeline v9.0.0 (*)
      │   └── libdd-trace-utils v11.0.0 (*)
      └── libdd-data-pipeline v9.0.0 (*)

error[unsound]: Rand is unsound with a custom logger using `rand::rng()`
    ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:224:1
    │
224 │ rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index
    │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unsound advisory detected
    │
    ├ ID: RUSTSEC-2026-0097
    ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0097
    ├ It has been reported (by [@lopopolo](https://github.com/lopopolo)) that the `rand` library is [unsound](https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library) (i.e. that safe code using the public API can cause Undefined Behaviour) when all the following conditions are met:
      
      - The `log` and `thread_rng` features are enabled
      - A [custom logger](https://docs.rs/log/latest/log/#implementing-a-logger) is defined
      - The custom logger accesses `rand::rng()` (previously `rand::thread_rng()`) and calls any `TryRng` (previously `RngCore`) methods on `ThreadRng`
      - The `ThreadRng` (attempts to) reseed while called from the custom logger (this happens every 64 kB of generated data)
      - Trace-level logging is enabled or warn-level logging is enabled and the random source (the `getrandom` crate) is unable to provide a new seed
      
      `TryRng` (previously `RngCore`) methods for `ThreadRng` use `unsafe` code to cast `*mut BlockRng<ReseedingCore>` to `&mut BlockRng<ReseedingCore>`. When all the above conditions are met this results in an aliased mutable reference, violating the Stacked Borrows rules. Miri is able to detect this violation in sample code. Since construction of [aliased mutable references is Undefined Behaviour](https://doc.rust-lang.org/stable/nomicon/references.html), the behaviour of optimized builds is hard to predict.
    ├ Announcement: https://github.com/rust-random/rand/pull/1763
    ├ Solution: Upgrade to >=0.10.1 OR <0.10.0, >=0.9.3 OR <0.9.0, >=0.8.6 (try `cargo update -p rand`)
    ├ rand v0.8.5
      ├── libdd-common v5.2.0
      │   ├── libdd-capabilities-impl v4.0.0
      │   │   ├── libdd-data-pipeline v9.0.0
      │   │   ├── libdd-shared-runtime v3.0.0
      │   │   │   ├── libdd-data-pipeline v9.0.0 (*)
      │   │   │   ├── libdd-dogstatsd-client v5.0.0
      │   │   │   │   ├── libdd-data-pipeline v9.0.0 (*)
      │   │   │   │   └── libdd-trace-stats v8.0.0
      │   │   │   │       └── libdd-data-pipeline v9.0.0 (*)
      │   │   │   ├── libdd-telemetry v7.0.0
      │   │   │   │   ├── libdd-data-pipeline v9.0.0 (*)
      │   │   │   │   └── libdd-trace-stats v8.0.0 (*)
      │   │   │   └── libdd-trace-stats v8.0.0 (*)
      │   │   ├── (dev) libdd-telemetry v7.0.0 (*)
      │   │   ├── libdd-trace-stats v8.0.0 (*)
      │   │   └── libdd-trace-utils v11.0.0
      │   │       ├── libdd-data-pipeline v9.0.0 (*)
      │   │       ├── libdd-data-pipeline-core v1.0.0
      │   │       │   └── libdd-data-pipeline v9.0.0 (*)
      │   │       ├── libdd-trace-obfuscation v7.0.0
      │   │       │   ├── libdd-data-pipeline v9.0.0 (*)
      │   │       │   ├── libdd-data-pipeline-core v1.0.0 (*)
      │   │       │   └── libdd-trace-stats v8.0.0 (*)
      │   │       ├── libdd-trace-stats v8.0.0 (*)
      │   │       └── (dev) libdd-trace-utils v11.0.0 (*)
      │   ├── libdd-data-pipeline v9.0.0 (*)
      │   ├── libdd-data-pipeline-core v1.0.0 (*)
      │   ├── libdd-dogstatsd-client v5.0.0 (*)
      │   ├── libdd-shared-runtime v3.0.0 (*)
      │   ├── libdd-telemetry v7.0.0 (*)
      │   ├── libdd-trace-obfuscation v7.0.0 (*)
      │   ├── libdd-trace-stats v8.0.0 (*)
      │   └── libdd-trace-utils v11.0.0 (*)
      ├── libdd-data-pipeline v9.0.0 (*)
      ├── (dev) libdd-ddsketch v1.1.1
      │   ├── libdd-data-pipeline v9.0.0 (*)
      │   ├── libdd-telemetry v7.0.0 (*)
      │   └── libdd-trace-stats v8.0.0 (*)
      ├── (dev) libdd-trace-normalization v4.0.0
      │   ├── libdd-data-pipeline v9.0.0 (*)
      │   └── libdd-trace-utils v11.0.0 (*)
      ├── (dev) libdd-trace-stats v8.0.0 (*)
      ├── libdd-trace-utils v11.0.0 (*)
      └── proptest v1.5.0
          ├── (dev) libdd-common v5.2.0 (*)
          └── (dev) libdd-tinybytes v1.1.2
              ├── libdd-data-pipeline v9.0.0 (*)
              ├── (dev) libdd-data-pipeline-core v1.0.0 (*)
              ├── (dev) libdd-tinybytes v1.1.2 (*)
              ├── (dev) libdd-trace-obfuscation v7.0.0 (*)
              └── libdd-trace-utils v11.0.0 (*)

error[vulnerability]: Denial of Service via Stack Exhaustion
    ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:297:1
    │
297 │ time 0.3.41 registry+https://github.com/rust-lang/crates.io-index
    │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
    │
    ├ ID: RUSTSEC-2026-0009
    ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0009
    ├ ## Impact
      
      When user-provided input is provided to any type that parses with the RFC 2822 format, a denial of
      service attack via stack exhaustion is possible. The attack relies on formally deprecated and
      rarely-used features that are part of the RFC 2822 format used in a malicious manner. Ordinary,
      non-malicious input will never encounter this scenario.
      
      ## Patches
      
      A limit to the depth of recursion was added in v0.3.47. From this version, an error will be returned
      rather than exhausting the stack.
      
      ## Workarounds
      
      Limiting the length of user input is the simplest way to avoid stack exhaustion, as the amount of
      the stack consumed would be at most a factor of the length of the input.
    ├ Announcement: https://github.com/time-rs/time/blob/main/CHANGELOG.md#0347-2026-02-05
    ├ Solution: Upgrade to >=0.3.47 (try `cargo update -p time`)
    ├ time v0.3.41
      └── tracing-appender v0.2.3
          └── libdd-log v1.0.0
              └── (dev) libdd-data-pipeline v9.0.0

advisories FAILED, bans ok, sources ok

📦 libdd-trace-utils - 3 error(s)

Show output
error[vulnerability]: Invalid pointer dereference in `fmt::Pointer` impl for `Atomic` and `Shared` when the underlying pointer is invalid
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:63:1
   │
63 │ crossbeam-epoch 0.9.18 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
   │
   ├ ID: RUSTSEC-2026-0204
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0204
   ├ Affected versions of `fmt::Display` dereference the underlying pointer. This causes a invalid pointer dereference e.g., when a pointer created with `Atomic::null` or `Shared::null`. `fmt::Debug` impls and pre-0.9 `fmt::Display` impls, which do not dereference pointers, are not affected by this issue.
   ├ Announcement: https://github.com/crossbeam-rs/crossbeam/pull/1276
   ├ Solution: Upgrade to >=0.9.20 (try `cargo update -p crossbeam-epoch`)
   ├ crossbeam-epoch v0.9.18
     └── crossbeam-deque v0.8.5
         └── rayon-core v1.12.1
             └── rayon v1.10.0
                 └── criterion v0.5.1
                     ├── libdd-common v5.2.0
                     │   ├── libdd-capabilities-impl v4.0.0
                     │   │   └── libdd-trace-utils v11.0.0
                     │   │       └── (dev) libdd-trace-utils v11.0.0 (*)
                     │   └── libdd-trace-utils v11.0.0 (*)
                     ├── (dev) libdd-trace-normalization v4.0.0
                     │   └── libdd-trace-utils v11.0.0 (*)
                     └── (dev) libdd-trace-utils v11.0.0 (*)

error[vulnerability]: h2 unbounded empty DATA frames
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:97:1
   │
97 │ h2 0.4.6 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
   │
   ├ ID: RUSTSEC-2026-0258
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0258
   ├ The h2 crate, used internally by hyper, had a flaw that would accept and queue empty DATA frames without limit.
     If streams were not actively drained, this could lead to unbounded memory usage, or a panic if the length overflows.
     
     Low severity.
     
     Patched in v0.4.16.
   ├ Announcement: https://github.com/hyperium/hyper/security/advisories/GHSA-q83h-524g-xf6h
   ├ Solution: Upgrade to >=0.4.16 (try `cargo update -p h2`)
   ├ h2 v0.4.6
     └── hyper v1.6.0
         ├── httpmock v0.8.0-alpha.1
         │   └── libdd-trace-utils v11.0.0
         │       └── (dev) libdd-trace-utils v11.0.0 (*)
         ├── hyper-rustls v0.27.7
         │   └── libdd-common v5.2.0
         │       ├── libdd-capabilities-impl v4.0.0
         │       │   └── libdd-trace-utils v11.0.0 (*)
         │       └── libdd-trace-utils v11.0.0 (*)
         ├── hyper-util v0.1.17
         │   ├── httpmock v0.8.0-alpha.1 (*)
         │   ├── hyper-rustls v0.27.7 (*)
         │   └── libdd-common v5.2.0 (*)
         ├── libdd-common v5.2.0 (*)
         └── libdd-trace-utils v11.0.0 (*)

error[unsound]: Rand is unsound with a custom logger using `rand::rng()`
    ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:184:1
    │
184 │ rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index
    │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unsound advisory detected
    │
    ├ ID: RUSTSEC-2026-0097
    ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0097
    ├ It has been reported (by [@lopopolo](https://github.com/lopopolo)) that the `rand` library is [unsound](https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library) (i.e. that safe code using the public API can cause Undefined Behaviour) when all the following conditions are met:
      
      - The `log` and `thread_rng` features are enabled
      - A [custom logger](https://docs.rs/log/latest/log/#implementing-a-logger) is defined
      - The custom logger accesses `rand::rng()` (previously `rand::thread_rng()`) and calls any `TryRng` (previously `RngCore`) methods on `ThreadRng`
      - The `ThreadRng` (attempts to) reseed while called from the custom logger (this happens every 64 kB of generated data)
      - Trace-level logging is enabled or warn-level logging is enabled and the random source (the `getrandom` crate) is unable to provide a new seed
      
      `TryRng` (previously `RngCore`) methods for `ThreadRng` use `unsafe` code to cast `*mut BlockRng<ReseedingCore>` to `&mut BlockRng<ReseedingCore>`. When all the above conditions are met this results in an aliased mutable reference, violating the Stacked Borrows rules. Miri is able to detect this violation in sample code. Since construction of [aliased mutable references is Undefined Behaviour](https://doc.rust-lang.org/stable/nomicon/references.html), the behaviour of optimized builds is hard to predict.
    ├ Announcement: https://github.com/rust-random/rand/pull/1763
    ├ Solution: Upgrade to >=0.10.1 OR <0.10.0, >=0.9.3 OR <0.9.0, >=0.8.6 (try `cargo update -p rand`)
    ├ rand v0.8.5
      ├── (dev) libdd-common v5.2.0
      │   ├── libdd-capabilities-impl v4.0.0
      │   │   └── libdd-trace-utils v11.0.0
      │   │       └── (dev) libdd-trace-utils v11.0.0 (*)
      │   └── libdd-trace-utils v11.0.0 (*)
      ├── (dev) libdd-trace-normalization v4.0.0
      │   └── libdd-trace-utils v11.0.0 (*)
      ├── libdd-trace-utils v11.0.0 (*)
      └── proptest v1.5.0
          ├── (dev) libdd-common v5.2.0 (*)
          └── (dev) libdd-tinybytes v1.1.2
              ├── (dev) libdd-tinybytes v1.1.2 (*)
              └── libdd-trace-utils v11.0.0 (*)

advisories FAILED, bans ok, sources ok

Updated: 2026-09-03 05:56:14 UTC | Commit: ff70244 | dependency-check job results

bm1549 added a commit that referenced this pull request Jun 27, 2026
The in-process exporter<->h2-server round trip is too timing-sensitive for
heavily contended CI runners: the client `send` has hit its request timeout on
macos-15 (GitHub) and the alpine/arm release-build matrix (GitLab) across
multiple runs, despite passing locally (20/20) and on less-loaded runners, and
despite the live backend verification in PR #2171 succeeding.

Mark it #[ignore] so it no longer runs in the default CI suites (it can't flake
the PR or burn release-build runner time), while keeping it runnable on demand
via `--run-ignored all`. The gRPC export path stays covered by this crate's unit
tests (ProstCodec, grpc_status_to_error, attach_metadata, build_grpc_channel,
builder dispatch, protocol parse) and by the live backend verification.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@dd-octo-sts

dd-octo-sts Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Artifact Size Benchmark Report

aarch64-alpine-linux-musl
Artifact Baseline Commit Change
/aarch64-alpine-linux-musl/lib/libdatadog_profiling.so 8.45 MB 9.02 MB +6.72% (+581.89 KB) 🚨
/aarch64-alpine-linux-musl/lib/libdatadog_profiling.a 91.30 MB 95.21 MB +4.28% (+3.91 MB) ⚠️
aarch64-unknown-linux-gnu
Artifact Baseline Commit Change
/aarch64-unknown-linux-gnu/lib/libdatadog_profiling.so 11.38 MB 12.15 MB +6.73% (+784.68 KB) 🚨
/aarch64-unknown-linux-gnu/lib/libdatadog_profiling.a 102.61 MB 106.50 MB +3.78% (+3.88 MB) ⚠️
libdatadog-x64-windows
Artifact Baseline Commit Change
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.dll 27.33 MB 28.81 MB +5.40% (+1.47 MB) 🚨
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.lib 96.08 KB 96.08 KB 0% (0 B) 👌
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.pdb 185.41 MB 190.13 MB +2.54% (+4.72 MB) ⚠️
/libdatadog-x64-windows/debug/static/datadog_profiling_ffi.lib 805.24 MB 810.11 MB +.60% (+4.87 MB) 🔍
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.dll 9.01 MB 9.64 MB +7.05% (+651.50 KB) 🚨
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.lib 96.08 KB 96.08 KB 0% (0 B) 👌
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.pdb 26.21 MB 27.24 MB +3.93% (+1.03 MB) ⚠️
/libdatadog-x64-windows/release/static/datadog_profiling_ffi.lib 52.22 MB 55.09 MB +5.50% (+2.87 MB) 🚨
libdatadog-x86-windows
Artifact Baseline Commit Change
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.dll 23.82 MB 25.18 MB +5.68% (+1.35 MB) 🚨
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.lib 97.58 KB 97.58 KB 0% (0 B) 👌
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.pdb 190.43 MB 195.50 MB +2.66% (+5.07 MB) ⚠️
/libdatadog-x86-windows/debug/static/datadog_profiling_ffi.lib 788.61 MB 794.81 MB +.78% (+6.20 MB) 🔍
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.dll 6.96 MB 7.45 MB +6.98% (+498.00 KB) 🚨
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.lib 97.58 KB 97.58 KB 0% (0 B) 👌
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.pdb 28.19 MB 29.33 MB +4.04% (+1.14 MB) ⚠️
/libdatadog-x86-windows/release/static/datadog_profiling_ffi.lib 49.70 MB 52.02 MB +4.65% (+2.31 MB) ⚠️
x86_64-alpine-linux-musl
Artifact Baseline Commit Change
/x86_64-alpine-linux-musl/lib/libdatadog_profiling.a 81.45 MB 84.99 MB +4.35% (+3.54 MB) ⚠️
/x86_64-alpine-linux-musl/lib/libdatadog_profiling.so 9.41 MB 10.00 MB +6.24% (+601.87 KB) 🚨
x86_64-unknown-linux-gnu
Artifact Baseline Commit Change
/x86_64-unknown-linux-gnu/lib/libdatadog_profiling.a 97.22 MB 101.11 MB +4.00% (+3.89 MB) ⚠️
/x86_64-unknown-linux-gnu/lib/libdatadog_profiling.so 11.46 MB 12.19 MB +6.42% (+754.60 KB) 🚨

@bm1549
bm1549 marked this pull request as ready for review June 29, 2026 17:17
@bm1549
bm1549 requested review from a team as code owners June 29, 2026 17:17
@bm1549
bm1549 requested review from vpellan and removed request for a team June 29, 2026 17:17

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9dcddce271

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread libdd-data-pipeline/src/otlp/grpc_exporter.rs Outdated
Comment thread libdd-data-pipeline/src/otlp/grpc_exporter.rs Outdated
bm1549 added a commit that referenced this pull request Jul 10, 2026
The in-process exporter<->h2-server round trip is too timing-sensitive for
heavily contended CI runners: the client `send` has hit its request timeout on
macos-15 (GitHub) and the alpine/arm release-build matrix (GitLab) across
multiple runs, despite passing locally (20/20) and on less-loaded runners, and
despite the live backend verification in PR #2171 succeeding.

Mark it #[ignore] so it no longer runs in the default CI suites (it can't flake
the PR or burn release-build runner time), while keeping it runnable on demand
via `--run-ignored all`. The gRPC export path stays covered by this crate's unit
tests (ProstCodec, grpc_status_to_error, attach_metadata, build_grpc_channel,
builder dispatch, protocol parse) and by the live backend verification.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@bm1549
bm1549 force-pushed the brian.marks/otlp-grpc-trace-export branch from 9dcddce to 093ed21 Compare July 10, 2026 22:35
@pr-commenter

pr-commenter Bot commented Jul 10, 2026

Copy link
Copy Markdown

Benchmarks

Comparison

Benchmark execution time: 2026-09-03 06:25:20

Comparing candidate commit a6ae5e4 in PR branch brian.marks/otlp-grpc-trace-export with baseline commit efbbf4c in branch main.

Found 8 performance improvements and 4 performance regressions! Performance is the same for 129 metrics, 0 unstable metrics.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

scenario:msgpack_decoder::v05/high_sharing/2000

  • 🟥 execution_time [+81.098µs; +81.547µs] or [+5.168%; +5.196%]
  • 🟥 throughput [-62956.661op/s; -62610.964op/s] or [-4.940%; -4.913%]

scenario:tags/replace_trace_tags

  • 🟥 execution_time [+239.209ns; +244.750ns] or [+9.147%; +9.359%]

scenario:tags/replace_trace_tags_v04

  • 🟥 execution_time [+156.842ns; +184.696ns] or [+5.568%; +6.557%]

scenario:vec_map/insert/128

  • 🟩 execution_time [-1.072µs; -1.065µs] or [-29.396%; -29.212%]
  • 🟩 throughput [+14496515.604op/s; +14606735.650op/s] or [+41.301%; +41.615%]

scenario:vec_map/insert/16

  • 🟩 execution_time [-145.354ns; -142.661ns] or [-25.117%; -24.651%]
  • 🟩 throughput [+9071539.897op/s; +9258318.908op/s] or [+32.807%; +33.482%]

scenario:vec_map/insert/64

  • 🟩 execution_time [-547.764ns; -543.776ns] or [-28.944%; -28.733%]
  • 🟩 throughput [+13650877.911op/s; +13762336.467op/s] or [+40.365%; +40.694%]

scenario:vec_map/insert/8

  • 🟩 execution_time [-71.620ns; -70.830ns] or [-24.236%; -23.969%]
  • 🟩 throughput [+8549399.476op/s; +8648681.020op/s] or [+31.579%; +31.945%]

Benchmark execution time: 2026-09-03 06:23:46

Comparing candidate commit a6ae5e4 in PR branch brian.marks/otlp-grpc-trace-export with baseline commit efbbf4c in branch main.

Found 0 performance improvements and 5 performance regressions! Performance is the same for 70 metrics, 10 unstable metrics.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

scenario:glob_matcher/ascii_wildcard_backtrack_match/wall_time

  • 🟥 execution_time [+17.824ns; +17.850ns] or [+48.229%; +48.299%]

scenario:glob_matcher/ascii_wildcard_heavy_backtrack/wall_time

  • 🟥 execution_time [+14.482ns; +14.518ns] or [+35.387%; +35.474%]

scenario:glob_matcher/ascii_wildcard_question_match/wall_time

  • 🟥 execution_time [+20.149ns; +20.173ns] or [+54.635%; +54.700%]

scenario:glob_matcher/ascii_wildcard_star_match/wall_time

  • 🟥 execution_time [+19.424ns; +19.450ns] or [+52.670%; +52.740%]

scenario:glob_matcher/unicode_exact_match/wall_time

  • 🟥 execution_time [+4.445ns; +4.510ns] or [+5.979%; +6.067%]

Candidate

Omitted due to size.

Baseline

Omitted due to size.

@yannham yannham left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First, apologies for waiting so long before giving you a first review. We'll avoid that kind of delay in the future.

As far as the PR goes, I have left a bunch of comments but there's no big technical blocker on my side. However I can't approve right away because the size impact is quite important. We don't have binary size quality gates (yet), but downstream consumers of libdatadog (tracers) do, which can lead to an unfortunate situation where this would get merged but tracers would be unable to update to future releases.

A first naive question: could/should this be feature-gated? I assume you'd want all tracers to support otlp out of the box, so the answers might be no, bu asking just in case.

A good test for the impact of the binary size increase: would you mind trying to create a PR against dd-trace-py pointing to this PR's libdatadog ref, and see if it triggers the size gates for e.g. serverless?

Comment thread libdd-data-pipeline/benches/otlp_grpc_export.rs Outdated
Comment thread libdd-data-pipeline/src/otlp/config.rs Outdated
Comment thread libdd-data-pipeline/src/otlp/config.rs Outdated
Comment thread libdd-data-pipeline/src/otlp/config.rs Outdated
Comment thread libdd-data-pipeline/src/otlp/config.rs Outdated
Comment thread libdd-data-pipeline/src/trace_exporter/mod.rs Outdated
Comment thread libdd-data-pipeline/src/trace_exporter/mod.rs Outdated
Comment thread libdd-data-pipeline/src/trace_exporter/mod.rs Outdated
Comment thread libdd-data-pipeline/Cargo.toml Outdated
#[cfg(test)]
mod grpc_export_tests {
use bytes::Bytes;
use h2::server;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for using a h2 server instead of the usual http mock server we've been using elsewhere in tests?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

httpmock here is HTTP/1.1-only (no http2 feature) and has no trailer support, so it can't serve gRPC - the unary status rides in HTTP/2 trailers. That's why the test hand-rolls an h2 server.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact httpmock does have an "http2" features, but it's just not advertised for some reason. It enables the corresponding features on hyper. I think in the transport PR you do some tests that might be hard to reproduce with the simplest API of httpmock, but it might be worth looking at.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to follow up here - httpmock has an undocumented http2 feature, but it can’t return HTTP/2 trailers. Since this test needs a trailing grpc-status: 0, it still needs the small h2 server.

@yannham

yannham commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

So, we've had a discussion with @VianneyRuhlmann about the whole worker situation. We believe we can side-step the "task in the background that needs to be restared" entirely by plugging in our own GrpcService implementation. It seems tonic provides a complicated default implementation through Channel with this background tower Service that reads through a channel and whatnot. But it's customizable and we can provide our own implementation of GrpcService instead, which seems to be rather simple (basically send some request). Doing so there's no background task anymore, we can get rid of the wait channel, and of the worker as well. It might even be possible to remove the "transport" feature entirely and save some binary size, though this has to be seen.

@bm1549
bm1549 force-pushed the brian.marks/otlp-grpc-trace-export branch from 093ed21 to 812e43b Compare July 24, 2026 20:44
@bm1549
bm1549 changed the base branch from main to brian.marks/otlp-grpc-transport July 24, 2026 20:44
@bm1549
bm1549 marked this pull request as draft July 24, 2026 20:44
@bm1549 bm1549 changed the title feat(data-pipeline): OTLP gRPC trace export feat(data-pipeline)!: OTLP gRPC trace export Jul 24, 2026
gh-worker-dd-mergequeue-cf854d Bot pushed a commit to DataDog/dd-trace-py that referenced this pull request Aug 5, 2026
## Description

When native OTLP trace export fails, `NativeWriter` currently reports its configured Datadog Agent intake URL even though libdatadog attempted the OTLP endpoint. This makes an OTLP protocol or connectivity error look like an Agent fallback.

Use the configured OTLP trace endpoint in failure diagnostics whenever OTLP trace export is active. Agent export diagnostics keep their existing behavior.

The original investigation also exposed a separate protocol mismatch: released versions send OTLP traces over HTTP/JSON, while the repro targeted the collector's gRPC port. HTTP/protobuf and gRPC support are already tracked by #18609, DataDog/libdatadog#2171, and DataDog/libdatadog#2273; this PR does not duplicate those transport changes.

## Testing

- `scripts/run-tests --venv 1ef5a52 -- -- tests/tracer/test_writer.py -k 'native_writer_reports_otlp_intake_endpoint or native_writer_stores_otlp_endpoint'` (Python 3.13; 2 passed)
- `scripts/lint checks`
- `scripts/lint style -- ddtrace/internal/writer/writer.py tests/tracer/test_writer.py`
- `scripts/lint spelling -- releasenotes/notes/fix-otlp-export-error-endpoint-6e7b7c8f756ef3a7.yaml`
- `riot run reno lint`

## Risks

Low. The change only affects the endpoint displayed in trace-export failure diagnostics when an OTLP endpoint is configured. It does not change routing, serialization, or retry behavior.

## Additional Notes

The OTLP/DDOT reference and the original handoff document were corrected separately to record that the old port-4317 reproduction was testing an HTTP exporter against a gRPC receiver.


Co-authored-by: munir.abdinur <munir.abdinur@datadoghq.com>
Base automatically changed from brian.marks/otlp-grpc-transport to main September 1, 2026 17:15
@bm1549
bm1549 force-pushed the brian.marks/otlp-grpc-trace-export branch from 812e43b to 13656d6 Compare September 1, 2026 18:52
Wires OTLP gRPC trace export into TraceExporter on top of the fork-safe
gRPC transport, selectable via OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=grpc.

OtlpProtocol gains a Grpc variant; the exporter dispatches through a new
OtlpExportMode (Http | Grpc) to either the existing HTTP path or the gRPC
transport (send_otlp_traces_grpc), with bounded exponential retry on
transient IO matching the HTTP path. The OTLP resource info is built once
at construction and shared by both paths. gRPC is native-only; wasm32
rejects it at build time. Includes a public-API end-to-end gRPC export test.

BREAKING CHANGE: adds the Grpc variant to the exhaustive public OtlpProtocol
enum, so exhaustive matches on it must add an arm. libdatadog consumers pin
by version and pick this up on the next release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@bm1549
bm1549 force-pushed the brian.marks/otlp-grpc-trace-export branch from 13656d6 to f0e93c2 Compare September 1, 2026 19:17
@bm1549
bm1549 marked this pull request as ready for review September 1, 2026 20:39
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 1, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-01T20:44:13.710778Z f0e93c2 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f0e93c2dce

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread libdd-data-pipeline/src/trace_exporter/builder.rs
Comment thread libdd-data-pipeline/src/otlp/grpc_exporter.rs Outdated
Default portless HTTP endpoints to port 80 while rejecting ambiguous authorities. Decode google.rpc.RetryInfo locally to avoid another tonic dependency, retry recoverable resource exhaustion with capped exponential delays, and share protobuf requests across attempts.
@bm1549
bm1549 requested a review from a team as a code owner September 1, 2026 21:43
/// ([`Self::set_otlp_metrics_endpoint`]).
///
/// OTLP and an agent URL may coexist: the agent URL is still useful for auxiliary
/// agent endpoints (info, stats) even when trace payloads are routed to OTLP.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for removing all of this? Did of it become obsolete?

Comment on lines +83 to +84
.checked_pow(attempt.saturating_sub(1))
.unwrap_or(u32::MAX);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.checked_pow(attempt.saturating_sub(1))
.unwrap_or(u32::MAX);
.saturating_pow(attempt.saturating_sub(1));

Comment on lines +86 to +87
.checked_mul(multiplier)
.unwrap_or(Duration::MAX)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.checked_mul(multiplier)
.unwrap_or(Duration::MAX)
.saturating_mul(multiplier)

// instead of going through the `Encoder`/`Decoder` traits (see `codec_tests`).
fn encode_into(item: T, dst: &mut impl bytes::BufMut) -> Result<(), Status> {
item.encode(dst)
fn encode_into(item: Arc<T>, dst: &mut impl bytes::BufMut) -> Result<(), Status> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, why do we need to switch to Arc here? Also, couldn't the encode just take a reference, leaving the choice to the caller whether to use Rc, Arc, & or whatnot

}

// Insert the pre-validated custom headers, the optional test-session token, and (when enabled) the
// client-computed-stats marker into the request metadata.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question: is this removal intentional?

@bm1549
bm1549 requested a review from a team as a code owner September 3, 2026 01:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants